Load libraries

This project uses renv to keep track of installed packages. Install renv if not installed and load dependencies with renv::restore().

install.packages("renv")
renv::restore()
library(readr)
library(dplyr)
library(tidyr)
library(reshape2)
library(GenomicRanges)
library(pheatmap)
library(tibble)
library(ggplot2)
library(stringr)
library(cowplot)
library(markdown)
library(RColorBrewer)
library(GenomicAlignments)
library(reshape2)

Read data

  1. Get list of samples
samples <- read_tsv("config/samples.tsv", show_col_types = FALSE)
units <- read_tsv("config/units.tsv", show_col_types = FALSE)
sample_units <- dplyr::left_join(samples, units, by = "sample_name") %>%
  unite(sample_unit, sample_name, unit_name, remove = FALSE)
sample_units
  1. Read Samtools idxstats to get human coverage for normalization

Notes:

idxstats_exogenousrna_dir <-
  "results/samtools_idxstats/exogenous_rna/"

idxstats_human_dir <-
  "results/samtools_idxstats/Homo_sapiens.GRCh38.dna.primary_assembly/"

bowtie2_human_logs <-
  "results/logs/bowtie2/Homo_sapiens.GRCh38.dna.primary_assembly/"

idxstats <- tibble()

for (row in seq_len(nrow(sample_units))) {
  sample <- sample_units[row, ]$sample_unit

  # Read `idsxstats` for exogenous mapped reads
  exogenous_rna_stats <- read_tsv(
    file.path(idxstats_exogenousrna_dir, sprintf("%s.bam.idxstats", sample)),
    col_names = c(
      "sequence_name", "sequence_length",
      "mapped_reads", "unmapped_reads"
    ),
    col_types = "ciii"
  )
  exogenous_rna_mapped_reads <- exogenous_rna_stats %>%
    filter(!sequence_name %in% c("*")) %>%
    select(sequence_name, mapped_reads) %>%
    mutate(sample = sample)

  # Read `idxstats` for human mapped reads
  human_stats <- read_tsv(
    file.path(idxstats_human_dir, sprintf("%s.bam.idxstats", sample)),
    col_names = c(
      "sequence_name", "sequence_length",
      "mapped_reads", "unmapped_reads"
    ),
    col_types = "ciii"
  )
  grch38_mapped_reads <- human_stats %>%
    filter(!sequence_name %in% c("*")) %>%
    select(mapped_reads) %>%
    sum()
  grch38_mapped_reads <- tibble(
    sequence_name = "grch38_mapped_reads",
    mapped_reads = grch38_mapped_reads,
    sample = sample
  )

  # Read bowtie2 logs for unmapped reads
  bowtie2_log <- readLines(
    file.path(bowtie2_human_logs, sprintf("%s.log", sample))
  )
  total_pairs <- strtoi(str_split(bowtie2_log[1], " ")[[1]][1])
  total_reads <- total_pairs * 2
  unmapped_reads <- tibble(
    sequence_name = "unmapped",
    mapped_reads = total_reads - grch38_mapped_reads$mapped_reads,
    sample = sample
  )

  # Consolidate counts for rows
  idxstats <- rbind(
    idxstats,
    exogenous_rna_mapped_reads,
    grch38_mapped_reads,
    unmapped_reads
  )
}
idxstats
  1. Read bedpe files to get exogenous rna coverage of paired reads
bedpe_data <- tibble()
for (sample in sample_units$sample_unit) {
  data <-
    readr::read_tsv(
      sprintf(
        "results/alignments/exogenous_rna/bedpe/%s.bedpe", sample
      ),
      col_names = c(
        "chrom1", "chrom1Start", "chrom1End",
        "chrom2", "chrom2Start", "chrom2End",
        "name", "score", "strand1", "strand2"
      ),
      col_types = "ciiciicicc"
    )
  bedpe_data <- tibble(rbind(
    bedpe_data,
    cbind(
      sample = sample,
      data
    )
  ))
}
bedpe_data

Coverage

Concordant vs Discordant paired reads

Concordant pairs are pairs of reads that:

  • Align on the same pegRNA
  • Align within 500 bp of each other
  • Align in the expected forward-reverse orientation (--> .. <--)

Discordant reads aligned but whose mate:

  • Did not align (on the pegRNA)
  • Aligned more than 500 bp away
  • Aligned in an unexpected orientation
## Config and function definition

bam_dir <- "results/alignments/exogenous_rna/sorted"

last_day <- 0
cols <- brewer.pal(n = 5, name = "RdBu")

concordant_cell_line_colors <- list(
  "Parental" = "#CA0020",
  "P1E10" = "#0571B0"
)

discordant_cell_line_colors <- list(
  "Parental" = "#F4A582",
  "P1E10" = "#92C5DE"
)

# Exogenous RNA mixtures
rna_mixes <- tibble()
for (mix in c("mastermix1", "mastermix2")) {
  t <- readDNAStringSet(sprintf("data/references/%s.fa", mix))
  rna_mixes <- rbind(rna_mixes, tibble(
    exogenous_rna = mix,
    rna_species = word(t@ranges@NAMES, 1),
    length = t@ranges@width
  ))
}

source("pegrna_plots.R")

VEGFA

rna_mix_rows <- rna_mixes %>% filter(grepl("VEGFA", rna_species))

for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
  for (row in seq_len(nrow(rna_mix_rows))) {
    rna_species <- rna_mix_rows[[row, "rna_species"]]
    mix <- rna_mix_rows[[row, "exogenous_rna"]]

    pegrna_plots(
      sequence_name = rna_species,
      normalization_factor = norm_factor,
      mix = mix,
      ylab = sprintf("%s coverage (normalized to %s)", mix, norm_factor),
    )
  }
}

FANCF

for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
  for (rna_species in rna_mixes %>%
    filter(grepl("FANCF", rna_species)) %>%
    pull(rna_species)) {
    pegrna_plots(
      sequence_name = rna_species,
      normalization_factor = norm_factor,
      ylab = sprintf("Coverage (normalized to %s)", norm_factor),
    )
  }
}

HEK3

for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
  for (rna_species in rna_mixes %>%
    filter(grepl("HEK3", rna_species)) %>%
    pull(rna_species)) {
    pegrna_plots(
      sequence_name = rna_species,
      normalization_factor = norm_factor,
      ylab = sprintf("Coverage (normalized to %s)", norm_factor),
    )
  }
}

DNMT1

for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
  for (rna_species in rna_mixes %>%
    filter(grepl("DNMT1", rna_species)) %>%
    pull(rna_species)) {
    pegrna_plots(
      sequence_name = rna_species,
      normalization_factor = norm_factor,
      ylab = sprintf("Coverage (normalized to %s)", norm_factor),
    )
  }
}

RUNX1

for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
  for (rna_species in rna_mixes %>%
    filter(grepl("RUNX1", rna_species)) %>%
    pull(rna_species)) {
    pegrna_plots(
      sequence_name = rna_species,
      normalization_factor = norm_factor,
      ylab = sprintf("Coverage (normalized to %s)", norm_factor),
    )
  }
}

EMX1

for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
  for (rna_species in rna_mixes %>%
    filter(grepl("EMX1", rna_species)) %>%
    pull(rna_species)) {
    pegrna_plots(
      sequence_name = rna_species,
      normalization_factor = norm_factor,
      ylab = sprintf("Coverage (normalized to %s)", norm_factor),
    )
  }
}

RNF2

for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
  for (rna_species in rna_mixes %>%
    filter(grepl("RNF2", rna_species)) %>%
    pull(rna_species)) {
    pegrna_plots(
      sequence_name = rna_species,
      normalization_factor = norm_factor,
      ylab = sprintf("Coverage (normalized to %s)", norm_factor)
    )
  }
}

Split by fragement start

VEGFA

rna_mix_rows <- rna_mixes %>% filter(grepl("VEGFA", rna_species))

for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
  for (row in seq_len(nrow(rna_mix_rows))) {
    rna_species <- rna_mix_rows[[row, "rna_species"]]
    mix <- rna_mix_rows[[row, "exogenous_rna"]]

    pegrna_plots(
      sequence_name = rna_species,
      normalization_factor = norm_factor,
      mix = mix,
      ylab = sprintf("%s coverage (normalized to %s)", mix, norm_factor),
      start_point = 10
    )
  }
}

FANCF

for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
  for (rna_species in rna_mixes %>%
    filter(grepl("FANCF", rna_species)) %>%
    pull(rna_species)) {
    pegrna_plots(
      sequence_name = rna_species,
      normalization_factor = norm_factor,
      ylab = sprintf("Coverage (normalized to %s)", norm_factor),
      start_point = 10
    )
  }
}

HEK3

for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
  for (rna_species in rna_mixes %>%
    filter(grepl("HEK3", rna_species)) %>%
    pull(rna_species)) {
    pegrna_plots(
      sequence_name = rna_species,
      normalization_factor = norm_factor,
      ylab = sprintf("Coverage (normalized to %s)", norm_factor),
      start_point = 10
    )
  }
}

DNMT1

for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
  for (rna_species in rna_mixes %>%
    filter(grepl("DNMT1", rna_species)) %>%
    pull(rna_species)) {
    pegrna_plots(
      sequence_name = rna_species,
      normalization_factor = norm_factor,
      ylab = sprintf("Coverage (normalized to %s)", norm_factor),
      start_point = 10
    )
  }
}

RUNX1

for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
  for (rna_species in rna_mixes %>%
    filter(grepl("RUNX1", rna_species)) %>%
    pull(rna_species)) {
    pegrna_plots(
      sequence_name = rna_species,
      normalization_factor = norm_factor,
      ylab = sprintf("Coverage (normalized to %s)", norm_factor),
      start_point = 10
    )
  }
}

EMX1

for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
  for (rna_species in rna_mixes %>%
    filter(grepl("EMX1", rna_species)) %>%
    pull(rna_species)) {
    pegrna_plots(
      sequence_name = rna_species,
      normalization_factor = norm_factor,
      ylab = sprintf("Coverage (normalized to %s)", norm_factor),
      start_point = 10
    )
  }
}

RNF2

for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
  for (rna_species in rna_mixes %>%
    filter(grepl("RNF2", rna_species)) %>%
    pull(rna_species)) {
    pegrna_plots(
      sequence_name = rna_species,
      normalization_factor = norm_factor,
      ylab = sprintf("Coverage (normalized to %s)", norm_factor),
      start_point = 10
    )
  }
}

LS0tCnRpdGxlOiAiQWRhbXNvbiBzbWFsbFJOQSAtIHBlZ1JOQSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIGNvZGVfZm9sZGluZzogaGlkZQotLS0KCiMjIExvYWQgbGlicmFyaWVzCgpUaGlzIHByb2plY3QgdXNlcyBbYHJlbnZgXShodHRwczovL3JzdHVkaW8uZ2l0aHViLmlvL3JlbnYvYXJ0aWNsZXMvcmVudi5odG1sKQp0byBrZWVwIHRyYWNrIG9mIGluc3RhbGxlZCBwYWNrYWdlcy4gSW5zdGFsbCBgcmVudmAgaWYgbm90IGluc3RhbGxlZCBhbmQgbG9hZApkZXBlbmRlbmNpZXMgd2l0aCBgcmVudjo6cmVzdG9yZSgpYC4KCmBgYHIKaW5zdGFsbC5wYWNrYWdlcygicmVudiIpCnJlbnY6OnJlc3RvcmUoKQpgYGAKCmBgYHtyIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkoR2Vub21pY1JhbmdlcykKbGlicmFyeShwaGVhdG1hcCkKbGlicmFyeSh0aWJibGUpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkobWFya2Rvd24pCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KEdlbm9taWNBbGlnbm1lbnRzKQpsaWJyYXJ5KHJlc2hhcGUyKQpgYGAKCiMjIFJlYWQgZGF0YQoKMS4gR2V0IGxpc3Qgb2Ygc2FtcGxlcwoKYGBge3J9CnNhbXBsZXMgPC0gcmVhZF90c3YoImNvbmZpZy9zYW1wbGVzLnRzdiIsIHNob3dfY29sX3R5cGVzID0gRkFMU0UpCnVuaXRzIDwtIHJlYWRfdHN2KCJjb25maWcvdW5pdHMudHN2Iiwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkKc2FtcGxlX3VuaXRzIDwtIGRwbHlyOjpsZWZ0X2pvaW4oc2FtcGxlcywgdW5pdHMsIGJ5ID0gInNhbXBsZV9uYW1lIikgJT4lCiAgdW5pdGUoc2FtcGxlX3VuaXQsIHNhbXBsZV9uYW1lLCB1bml0X25hbWUsIHJlbW92ZSA9IEZBTFNFKQpzYW1wbGVfdW5pdHMKYGBgCgoyLiBSZWFkIFNhbXRvb2xzIGBpZHhzdGF0c2AgdG8gZ2V0IGh1bWFuIGNvdmVyYWdlIGZvciBub3JtYWxpemF0aW9uCgpOb3RlczoKCiogVGhlIGNvdW50cyBpbmNsdWRlIHRoZSB0b3RhbCBudW1iZXIgb2YgcmVhZHMgYWxpZ25lZCwgdGhleSAKICBhcmUgbm90IGxpbWl0ZWQgdG8gdW5pcXVlbHkgYWxpZ25lZCByZWFkcy4KKiBUaGUgY291bnRzIGFyZSByZWFkcywgbm90IHBhaXJzIG9yIGZyYWdtZW50cwoKYGBge3J9CmlkeHN0YXRzX2V4b2dlbm91c3JuYV9kaXIgPC0KICAicmVzdWx0cy9zYW10b29sc19pZHhzdGF0cy9leG9nZW5vdXNfcm5hLyIKCmlkeHN0YXRzX2h1bWFuX2RpciA8LQogICJyZXN1bHRzL3NhbXRvb2xzX2lkeHN0YXRzL0hvbW9fc2FwaWVucy5HUkNoMzguZG5hLnByaW1hcnlfYXNzZW1ibHkvIgoKYm93dGllMl9odW1hbl9sb2dzIDwtCiAgInJlc3VsdHMvbG9ncy9ib3d0aWUyL0hvbW9fc2FwaWVucy5HUkNoMzguZG5hLnByaW1hcnlfYXNzZW1ibHkvIgoKaWR4c3RhdHMgPC0gdGliYmxlKCkKCmZvciAocm93IGluIHNlcV9sZW4obnJvdyhzYW1wbGVfdW5pdHMpKSkgewogIHNhbXBsZSA8LSBzYW1wbGVfdW5pdHNbcm93LCBdJHNhbXBsZV91bml0CgogICMgUmVhZCBgaWRzeHN0YXRzYCBmb3IgZXhvZ2Vub3VzIG1hcHBlZCByZWFkcwogIGV4b2dlbm91c19ybmFfc3RhdHMgPC0gcmVhZF90c3YoCiAgICBmaWxlLnBhdGgoaWR4c3RhdHNfZXhvZ2Vub3Vzcm5hX2Rpciwgc3ByaW50ZigiJXMuYmFtLmlkeHN0YXRzIiwgc2FtcGxlKSksCiAgICBjb2xfbmFtZXMgPSBjKAogICAgICAic2VxdWVuY2VfbmFtZSIsICJzZXF1ZW5jZV9sZW5ndGgiLAogICAgICAibWFwcGVkX3JlYWRzIiwgInVubWFwcGVkX3JlYWRzIgogICAgKSwKICAgIGNvbF90eXBlcyA9ICJjaWlpIgogICkKICBleG9nZW5vdXNfcm5hX21hcHBlZF9yZWFkcyA8LSBleG9nZW5vdXNfcm5hX3N0YXRzICU+JQogICAgZmlsdGVyKCFzZXF1ZW5jZV9uYW1lICVpbiUgYygiKiIpKSAlPiUKICAgIHNlbGVjdChzZXF1ZW5jZV9uYW1lLCBtYXBwZWRfcmVhZHMpICU+JQogICAgbXV0YXRlKHNhbXBsZSA9IHNhbXBsZSkKCiAgIyBSZWFkIGBpZHhzdGF0c2AgZm9yIGh1bWFuIG1hcHBlZCByZWFkcwogIGh1bWFuX3N0YXRzIDwtIHJlYWRfdHN2KAogICAgZmlsZS5wYXRoKGlkeHN0YXRzX2h1bWFuX2Rpciwgc3ByaW50ZigiJXMuYmFtLmlkeHN0YXRzIiwgc2FtcGxlKSksCiAgICBjb2xfbmFtZXMgPSBjKAogICAgICAic2VxdWVuY2VfbmFtZSIsICJzZXF1ZW5jZV9sZW5ndGgiLAogICAgICAibWFwcGVkX3JlYWRzIiwgInVubWFwcGVkX3JlYWRzIgogICAgKSwKICAgIGNvbF90eXBlcyA9ICJjaWlpIgogICkKICBncmNoMzhfbWFwcGVkX3JlYWRzIDwtIGh1bWFuX3N0YXRzICU+JQogICAgZmlsdGVyKCFzZXF1ZW5jZV9uYW1lICVpbiUgYygiKiIpKSAlPiUKICAgIHNlbGVjdChtYXBwZWRfcmVhZHMpICU+JQogICAgc3VtKCkKICBncmNoMzhfbWFwcGVkX3JlYWRzIDwtIHRpYmJsZSgKICAgIHNlcXVlbmNlX25hbWUgPSAiZ3JjaDM4X21hcHBlZF9yZWFkcyIsCiAgICBtYXBwZWRfcmVhZHMgPSBncmNoMzhfbWFwcGVkX3JlYWRzLAogICAgc2FtcGxlID0gc2FtcGxlCiAgKQoKICAjIFJlYWQgYm93dGllMiBsb2dzIGZvciB1bm1hcHBlZCByZWFkcwogIGJvd3RpZTJfbG9nIDwtIHJlYWRMaW5lcygKICAgIGZpbGUucGF0aChib3d0aWUyX2h1bWFuX2xvZ3MsIHNwcmludGYoIiVzLmxvZyIsIHNhbXBsZSkpCiAgKQogIHRvdGFsX3BhaXJzIDwtIHN0cnRvaShzdHJfc3BsaXQoYm93dGllMl9sb2dbMV0sICIgIilbWzFdXVsxXSkKICB0b3RhbF9yZWFkcyA8LSB0b3RhbF9wYWlycyAqIDIKICB1bm1hcHBlZF9yZWFkcyA8LSB0aWJibGUoCiAgICBzZXF1ZW5jZV9uYW1lID0gInVubWFwcGVkIiwKICAgIG1hcHBlZF9yZWFkcyA9IHRvdGFsX3JlYWRzIC0gZ3JjaDM4X21hcHBlZF9yZWFkcyRtYXBwZWRfcmVhZHMsCiAgICBzYW1wbGUgPSBzYW1wbGUKICApCgogICMgQ29uc29saWRhdGUgY291bnRzIGZvciByb3dzCiAgaWR4c3RhdHMgPC0gcmJpbmQoCiAgICBpZHhzdGF0cywKICAgIGV4b2dlbm91c19ybmFfbWFwcGVkX3JlYWRzLAogICAgZ3JjaDM4X21hcHBlZF9yZWFkcywKICAgIHVubWFwcGVkX3JlYWRzCiAgKQp9CmlkeHN0YXRzCmBgYAoKMy4gUmVhZCBgYmVkcGVgIGZpbGVzIHRvIGdldCBleG9nZW5vdXMgcm5hIGNvdmVyYWdlIG9mIHBhaXJlZCByZWFkcwoKYGBge3J9CmJlZHBlX2RhdGEgPC0gdGliYmxlKCkKZm9yIChzYW1wbGUgaW4gc2FtcGxlX3VuaXRzJHNhbXBsZV91bml0KSB7CiAgZGF0YSA8LQogICAgcmVhZHI6OnJlYWRfdHN2KAogICAgICBzcHJpbnRmKAogICAgICAgICJyZXN1bHRzL2FsaWdubWVudHMvZXhvZ2Vub3VzX3JuYS9iZWRwZS8lcy5iZWRwZSIsIHNhbXBsZQogICAgICApLAogICAgICBjb2xfbmFtZXMgPSBjKAogICAgICAgICJjaHJvbTEiLCAiY2hyb20xU3RhcnQiLCAiY2hyb20xRW5kIiwKICAgICAgICAiY2hyb20yIiwgImNocm9tMlN0YXJ0IiwgImNocm9tMkVuZCIsCiAgICAgICAgIm5hbWUiLCAic2NvcmUiLCAic3RyYW5kMSIsICJzdHJhbmQyIgogICAgICApLAogICAgICBjb2xfdHlwZXMgPSAiY2lpY2lpY2ljYyIKICAgICkKICBiZWRwZV9kYXRhIDwtIHRpYmJsZShyYmluZCgKICAgIGJlZHBlX2RhdGEsCiAgICBjYmluZCgKICAgICAgc2FtcGxlID0gc2FtcGxlLAogICAgICBkYXRhCiAgICApCiAgKSkKfQpiZWRwZV9kYXRhCmBgYAoKIyMgQ292ZXJhZ2UKCiMjIyBDb25jb3JkYW50IHZzIERpc2NvcmRhbnQgcGFpcmVkIHJlYWRzCgpDb25jb3JkYW50IHBhaXJzIGFyZSBwYWlycyBvZiByZWFkcyB0aGF0OgoKKiBBbGlnbiBvbiB0aGUgc2FtZSBwZWdSTkEKKiBBbGlnbiB3aXRoaW4gNTAwIGJwIG9mIGVhY2ggb3RoZXIKKiBBbGlnbiBpbiB0aGUgZXhwZWN0ZWQgZm9yd2FyZC1yZXZlcnNlIG9yaWVudGF0aW9uIChgLS0+IC4uIDwtLWApCgpEaXNjb3JkYW50IHJlYWRzIGFsaWduZWQgYnV0IHdob3NlIG1hdGU6CgoqIERpZCBub3QgYWxpZ24gKG9uIHRoZSBwZWdSTkEpCiogQWxpZ25lZCBtb3JlIHRoYW4gNTAwIGJwIGF3YXkKKiBBbGlnbmVkIGluIGFuIHVuZXhwZWN0ZWQgb3JpZW50YXRpb24KCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KIyMgQ29uZmlnIGFuZCBmdW5jdGlvbiBkZWZpbml0aW9uCgpiYW1fZGlyIDwtICJyZXN1bHRzL2FsaWdubWVudHMvZXhvZ2Vub3VzX3JuYS9zb3J0ZWQiCgpsYXN0X2RheSA8LSAwCmNvbHMgPC0gYnJld2VyLnBhbChuID0gNSwgbmFtZSA9ICJSZEJ1IikKCmNvbmNvcmRhbnRfY2VsbF9saW5lX2NvbG9ycyA8LSBsaXN0KAogICJQYXJlbnRhbCIgPSAiI0NBMDAyMCIsCiAgIlAxRTEwIiA9ICIjMDU3MUIwIgopCgpkaXNjb3JkYW50X2NlbGxfbGluZV9jb2xvcnMgPC0gbGlzdCgKICAiUGFyZW50YWwiID0gIiNGNEE1ODIiLAogICJQMUUxMCIgPSAiIzkyQzVERSIKKQoKIyBFeG9nZW5vdXMgUk5BIG1peHR1cmVzCnJuYV9taXhlcyA8LSB0aWJibGUoKQpmb3IgKG1peCBpbiBjKCJtYXN0ZXJtaXgxIiwgIm1hc3Rlcm1peDIiKSkgewogIHQgPC0gcmVhZEROQVN0cmluZ1NldChzcHJpbnRmKCJkYXRhL3JlZmVyZW5jZXMvJXMuZmEiLCBtaXgpKQogIHJuYV9taXhlcyA8LSByYmluZChybmFfbWl4ZXMsIHRpYmJsZSgKICAgIGV4b2dlbm91c19ybmEgPSBtaXgsCiAgICBybmFfc3BlY2llcyA9IHdvcmQodEByYW5nZXNATkFNRVMsIDEpLAogICAgbGVuZ3RoID0gdEByYW5nZXNAd2lkdGgKICApKQp9Cgpzb3VyY2UoInBlZ3JuYV9wbG90cy5SIikKYGBgCgojIyMjIFZFR0ZBCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CnJuYV9taXhfcm93cyA8LSBybmFfbWl4ZXMgJT4lIGZpbHRlcihncmVwbCgiVkVHRkEiLCBybmFfc3BlY2llcykpCgpmb3IgKG5vcm1fZmFjdG9yIGluIGMoImV4b2dlbm91c19ybmFfbWFwcGVkX3JlYWRzIiwgImdyY2gzOF9tYXBwZWRfcmVhZHMiKSkgewogIGZvciAocm93IGluIHNlcV9sZW4obnJvdyhybmFfbWl4X3Jvd3MpKSkgewogICAgcm5hX3NwZWNpZXMgPC0gcm5hX21peF9yb3dzW1tyb3csICJybmFfc3BlY2llcyJdXQogICAgbWl4IDwtIHJuYV9taXhfcm93c1tbcm93LCAiZXhvZ2Vub3VzX3JuYSJdXQoKICAgIHBlZ3JuYV9wbG90cygKICAgICAgc2VxdWVuY2VfbmFtZSA9IHJuYV9zcGVjaWVzLAogICAgICBub3JtYWxpemF0aW9uX2ZhY3RvciA9IG5vcm1fZmFjdG9yLAogICAgICBtaXggPSBtaXgsCiAgICAgIHlsYWIgPSBzcHJpbnRmKCIlcyBjb3ZlcmFnZSAobm9ybWFsaXplZCB0byAlcykiLCBtaXgsIG5vcm1fZmFjdG9yKSwKICAgICkKICB9Cn0KYGBgCgojIyMjIEZBTkNGCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CmZvciAobm9ybV9mYWN0b3IgaW4gYygiZXhvZ2Vub3VzX3JuYV9tYXBwZWRfcmVhZHMiLCAiZ3JjaDM4X21hcHBlZF9yZWFkcyIpKSB7CiAgZm9yIChybmFfc3BlY2llcyBpbiBybmFfbWl4ZXMgJT4lCiAgICBmaWx0ZXIoZ3JlcGwoIkZBTkNGIiwgcm5hX3NwZWNpZXMpKSAlPiUKICAgIHB1bGwocm5hX3NwZWNpZXMpKSB7CiAgICBwZWdybmFfcGxvdHMoCiAgICAgIHNlcXVlbmNlX25hbWUgPSBybmFfc3BlY2llcywKICAgICAgbm9ybWFsaXphdGlvbl9mYWN0b3IgPSBub3JtX2ZhY3RvciwKICAgICAgeWxhYiA9IHNwcmludGYoIkNvdmVyYWdlIChub3JtYWxpemVkIHRvICVzKSIsIG5vcm1fZmFjdG9yKSwKICAgICkKICB9Cn0KYGBgCgojIyMjIEhFSzMKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KZm9yIChub3JtX2ZhY3RvciBpbiBjKCJleG9nZW5vdXNfcm5hX21hcHBlZF9yZWFkcyIsICJncmNoMzhfbWFwcGVkX3JlYWRzIikpIHsKICBmb3IgKHJuYV9zcGVjaWVzIGluIHJuYV9taXhlcyAlPiUKICAgIGZpbHRlcihncmVwbCgiSEVLMyIsIHJuYV9zcGVjaWVzKSkgJT4lCiAgICBwdWxsKHJuYV9zcGVjaWVzKSkgewogICAgcGVncm5hX3Bsb3RzKAogICAgICBzZXF1ZW5jZV9uYW1lID0gcm5hX3NwZWNpZXMsCiAgICAgIG5vcm1hbGl6YXRpb25fZmFjdG9yID0gbm9ybV9mYWN0b3IsCiAgICAgIHlsYWIgPSBzcHJpbnRmKCJDb3ZlcmFnZSAobm9ybWFsaXplZCB0byAlcykiLCBub3JtX2ZhY3RvciksCiAgICApCiAgfQp9CmBgYAoKCgojIyMjIEROTVQxCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CmZvciAobm9ybV9mYWN0b3IgaW4gYygiZXhvZ2Vub3VzX3JuYV9tYXBwZWRfcmVhZHMiLCAiZ3JjaDM4X21hcHBlZF9yZWFkcyIpKSB7CiAgZm9yIChybmFfc3BlY2llcyBpbiBybmFfbWl4ZXMgJT4lCiAgICBmaWx0ZXIoZ3JlcGwoIkROTVQxIiwgcm5hX3NwZWNpZXMpKSAlPiUKICAgIHB1bGwocm5hX3NwZWNpZXMpKSB7CiAgICBwZWdybmFfcGxvdHMoCiAgICAgIHNlcXVlbmNlX25hbWUgPSBybmFfc3BlY2llcywKICAgICAgbm9ybWFsaXphdGlvbl9mYWN0b3IgPSBub3JtX2ZhY3RvciwKICAgICAgeWxhYiA9IHNwcmludGYoIkNvdmVyYWdlIChub3JtYWxpemVkIHRvICVzKSIsIG5vcm1fZmFjdG9yKSwKICAgICkKICB9Cn0KYGBgCgoKIyMjIyBSVU5YMQoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQpmb3IgKG5vcm1fZmFjdG9yIGluIGMoImV4b2dlbm91c19ybmFfbWFwcGVkX3JlYWRzIiwgImdyY2gzOF9tYXBwZWRfcmVhZHMiKSkgewogIGZvciAocm5hX3NwZWNpZXMgaW4gcm5hX21peGVzICU+JQogICAgZmlsdGVyKGdyZXBsKCJSVU5YMSIsIHJuYV9zcGVjaWVzKSkgJT4lCiAgICBwdWxsKHJuYV9zcGVjaWVzKSkgewogICAgcGVncm5hX3Bsb3RzKAogICAgICBzZXF1ZW5jZV9uYW1lID0gcm5hX3NwZWNpZXMsCiAgICAgIG5vcm1hbGl6YXRpb25fZmFjdG9yID0gbm9ybV9mYWN0b3IsCiAgICAgIHlsYWIgPSBzcHJpbnRmKCJDb3ZlcmFnZSAobm9ybWFsaXplZCB0byAlcykiLCBub3JtX2ZhY3RvciksCiAgICApCiAgfQp9CmBgYAoKIyMjIyBFTVgxCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CmZvciAobm9ybV9mYWN0b3IgaW4gYygiZXhvZ2Vub3VzX3JuYV9tYXBwZWRfcmVhZHMiLCAiZ3JjaDM4X21hcHBlZF9yZWFkcyIpKSB7CiAgZm9yIChybmFfc3BlY2llcyBpbiBybmFfbWl4ZXMgJT4lCiAgICBmaWx0ZXIoZ3JlcGwoIkVNWDEiLCBybmFfc3BlY2llcykpICU+JQogICAgcHVsbChybmFfc3BlY2llcykpIHsKICAgIHBlZ3JuYV9wbG90cygKICAgICAgc2VxdWVuY2VfbmFtZSA9IHJuYV9zcGVjaWVzLAogICAgICBub3JtYWxpemF0aW9uX2ZhY3RvciA9IG5vcm1fZmFjdG9yLAogICAgICB5bGFiID0gc3ByaW50ZigiQ292ZXJhZ2UgKG5vcm1hbGl6ZWQgdG8gJXMpIiwgbm9ybV9mYWN0b3IpLAogICAgKQogIH0KfQpgYGAKCiMjIyMgUk5GMgoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQpmb3IgKG5vcm1fZmFjdG9yIGluIGMoImV4b2dlbm91c19ybmFfbWFwcGVkX3JlYWRzIiwgImdyY2gzOF9tYXBwZWRfcmVhZHMiKSkgewogIGZvciAocm5hX3NwZWNpZXMgaW4gcm5hX21peGVzICU+JQogICAgZmlsdGVyKGdyZXBsKCJSTkYyIiwgcm5hX3NwZWNpZXMpKSAlPiUKICAgIHB1bGwocm5hX3NwZWNpZXMpKSB7CiAgICBwZWdybmFfcGxvdHMoCiAgICAgIHNlcXVlbmNlX25hbWUgPSBybmFfc3BlY2llcywKICAgICAgbm9ybWFsaXphdGlvbl9mYWN0b3IgPSBub3JtX2ZhY3RvciwKICAgICAgeWxhYiA9IHNwcmludGYoIkNvdmVyYWdlIChub3JtYWxpemVkIHRvICVzKSIsIG5vcm1fZmFjdG9yKQogICAgKQogIH0KfQpgYGAKCgoKIyMjIFNwbGl0IGJ5IGZyYWdlbWVudCBzdGFydAoKIyMjIyBWRUdGQQoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQpybmFfbWl4X3Jvd3MgPC0gcm5hX21peGVzICU+JSBmaWx0ZXIoZ3JlcGwoIlZFR0ZBIiwgcm5hX3NwZWNpZXMpKQoKZm9yIChub3JtX2ZhY3RvciBpbiBjKCJleG9nZW5vdXNfcm5hX21hcHBlZF9yZWFkcyIsICJncmNoMzhfbWFwcGVkX3JlYWRzIikpIHsKICBmb3IgKHJvdyBpbiBzZXFfbGVuKG5yb3cocm5hX21peF9yb3dzKSkpIHsKICAgIHJuYV9zcGVjaWVzIDwtIHJuYV9taXhfcm93c1tbcm93LCAicm5hX3NwZWNpZXMiXV0KICAgIG1peCA8LSBybmFfbWl4X3Jvd3NbW3JvdywgImV4b2dlbm91c19ybmEiXV0KCiAgICBwZWdybmFfcGxvdHMoCiAgICAgIHNlcXVlbmNlX25hbWUgPSBybmFfc3BlY2llcywKICAgICAgbm9ybWFsaXphdGlvbl9mYWN0b3IgPSBub3JtX2ZhY3RvciwKICAgICAgbWl4ID0gbWl4LAogICAgICB5bGFiID0gc3ByaW50ZigiJXMgY292ZXJhZ2UgKG5vcm1hbGl6ZWQgdG8gJXMpIiwgbWl4LCBub3JtX2ZhY3RvciksCiAgICAgIHN0YXJ0X3BvaW50ID0gMTAKICAgICkKICB9Cn0KYGBgCgoKIyMjIyBGQU5DRgoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQpmb3IgKG5vcm1fZmFjdG9yIGluIGMoImV4b2dlbm91c19ybmFfbWFwcGVkX3JlYWRzIiwgImdyY2gzOF9tYXBwZWRfcmVhZHMiKSkgewogIGZvciAocm5hX3NwZWNpZXMgaW4gcm5hX21peGVzICU+JQogICAgZmlsdGVyKGdyZXBsKCJGQU5DRiIsIHJuYV9zcGVjaWVzKSkgJT4lCiAgICBwdWxsKHJuYV9zcGVjaWVzKSkgewogICAgcGVncm5hX3Bsb3RzKAogICAgICBzZXF1ZW5jZV9uYW1lID0gcm5hX3NwZWNpZXMsCiAgICAgIG5vcm1hbGl6YXRpb25fZmFjdG9yID0gbm9ybV9mYWN0b3IsCiAgICAgIHlsYWIgPSBzcHJpbnRmKCJDb3ZlcmFnZSAobm9ybWFsaXplZCB0byAlcykiLCBub3JtX2ZhY3RvciksCiAgICAgIHN0YXJ0X3BvaW50ID0gMTAKICAgICkKICB9Cn0KYGBgCgojIyMjIEhFSzMKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KZm9yIChub3JtX2ZhY3RvciBpbiBjKCJleG9nZW5vdXNfcm5hX21hcHBlZF9yZWFkcyIsICJncmNoMzhfbWFwcGVkX3JlYWRzIikpIHsKICBmb3IgKHJuYV9zcGVjaWVzIGluIHJuYV9taXhlcyAlPiUKICAgIGZpbHRlcihncmVwbCgiSEVLMyIsIHJuYV9zcGVjaWVzKSkgJT4lCiAgICBwdWxsKHJuYV9zcGVjaWVzKSkgewogICAgcGVncm5hX3Bsb3RzKAogICAgICBzZXF1ZW5jZV9uYW1lID0gcm5hX3NwZWNpZXMsCiAgICAgIG5vcm1hbGl6YXRpb25fZmFjdG9yID0gbm9ybV9mYWN0b3IsCiAgICAgIHlsYWIgPSBzcHJpbnRmKCJDb3ZlcmFnZSAobm9ybWFsaXplZCB0byAlcykiLCBub3JtX2ZhY3RvciksCiAgICAgIHN0YXJ0X3BvaW50ID0gMTAKICAgICkKICB9Cn0KYGBgCgoKCiMjIyMgRE5NVDEKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KZm9yIChub3JtX2ZhY3RvciBpbiBjKCJleG9nZW5vdXNfcm5hX21hcHBlZF9yZWFkcyIsICJncmNoMzhfbWFwcGVkX3JlYWRzIikpIHsKICBmb3IgKHJuYV9zcGVjaWVzIGluIHJuYV9taXhlcyAlPiUKICAgIGZpbHRlcihncmVwbCgiRE5NVDEiLCBybmFfc3BlY2llcykpICU+JQogICAgcHVsbChybmFfc3BlY2llcykpIHsKICAgIHBlZ3JuYV9wbG90cygKICAgICAgc2VxdWVuY2VfbmFtZSA9IHJuYV9zcGVjaWVzLAogICAgICBub3JtYWxpemF0aW9uX2ZhY3RvciA9IG5vcm1fZmFjdG9yLAogICAgICB5bGFiID0gc3ByaW50ZigiQ292ZXJhZ2UgKG5vcm1hbGl6ZWQgdG8gJXMpIiwgbm9ybV9mYWN0b3IpLAogICAgICBzdGFydF9wb2ludCA9IDEwCiAgICApCiAgfQp9CmBgYAoKCiMjIyMgUlVOWDEKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KZm9yIChub3JtX2ZhY3RvciBpbiBjKCJleG9nZW5vdXNfcm5hX21hcHBlZF9yZWFkcyIsICJncmNoMzhfbWFwcGVkX3JlYWRzIikpIHsKICBmb3IgKHJuYV9zcGVjaWVzIGluIHJuYV9taXhlcyAlPiUKICAgIGZpbHRlcihncmVwbCgiUlVOWDEiLCBybmFfc3BlY2llcykpICU+JQogICAgcHVsbChybmFfc3BlY2llcykpIHsKICAgIHBlZ3JuYV9wbG90cygKICAgICAgc2VxdWVuY2VfbmFtZSA9IHJuYV9zcGVjaWVzLAogICAgICBub3JtYWxpemF0aW9uX2ZhY3RvciA9IG5vcm1fZmFjdG9yLAogICAgICB5bGFiID0gc3ByaW50ZigiQ292ZXJhZ2UgKG5vcm1hbGl6ZWQgdG8gJXMpIiwgbm9ybV9mYWN0b3IpLAogICAgICBzdGFydF9wb2ludCA9IDEwCiAgICApCiAgfQp9CmBgYAoKIyMjIyBFTVgxCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CmZvciAobm9ybV9mYWN0b3IgaW4gYygiZXhvZ2Vub3VzX3JuYV9tYXBwZWRfcmVhZHMiLCAiZ3JjaDM4X21hcHBlZF9yZWFkcyIpKSB7CiAgZm9yIChybmFfc3BlY2llcyBpbiBybmFfbWl4ZXMgJT4lCiAgICBmaWx0ZXIoZ3JlcGwoIkVNWDEiLCBybmFfc3BlY2llcykpICU+JQogICAgcHVsbChybmFfc3BlY2llcykpIHsKICAgIHBlZ3JuYV9wbG90cygKICAgICAgc2VxdWVuY2VfbmFtZSA9IHJuYV9zcGVjaWVzLAogICAgICBub3JtYWxpemF0aW9uX2ZhY3RvciA9IG5vcm1fZmFjdG9yLAogICAgICB5bGFiID0gc3ByaW50ZigiQ292ZXJhZ2UgKG5vcm1hbGl6ZWQgdG8gJXMpIiwgbm9ybV9mYWN0b3IpLAogICAgICBzdGFydF9wb2ludCA9IDEwCiAgICApCiAgfQp9CmBgYAoKIyMjIyBSTkYyCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CmZvciAobm9ybV9mYWN0b3IgaW4gYygiZXhvZ2Vub3VzX3JuYV9tYXBwZWRfcmVhZHMiLCAiZ3JjaDM4X21hcHBlZF9yZWFkcyIpKSB7CiAgZm9yIChybmFfc3BlY2llcyBpbiBybmFfbWl4ZXMgJT4lCiAgICBmaWx0ZXIoZ3JlcGwoIlJORjIiLCBybmFfc3BlY2llcykpICU+JQogICAgcHVsbChybmFfc3BlY2llcykpIHsKICAgIHBlZ3JuYV9wbG90cygKICAgICAgc2VxdWVuY2VfbmFtZSA9IHJuYV9zcGVjaWVzLAogICAgICBub3JtYWxpemF0aW9uX2ZhY3RvciA9IG5vcm1fZmFjdG9yLAogICAgICB5bGFiID0gc3ByaW50ZigiQ292ZXJhZ2UgKG5vcm1hbGl6ZWQgdG8gJXMpIiwgbm9ybV9mYWN0b3IpLAogICAgICBzdGFydF9wb2ludCA9IDEwCiAgICApCiAgfQp9CmBgYAo=